package antLogic;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: Mark the intern
 * Date: 12-Jul-2007
 * Time: 2:37:01 PM
 */
public class World extends Thread {

    protected Integer width;
    protected Integer height;
    protected Coordinate antHillLocation;
    protected Integer numAntsPerLoop;
    protected Integer numberOfAntStepsInOneUnit;
    private Date now;

    protected HashMap<Integer, Coordinate> antLocations;

    protected Map map;

    private Integer idCount;

    private Integer sleepTime;

    protected World(int width, int height, Coordinate antHillLocation, int numberOfAntStepsInOneUnit, int numAntsPerLoop, int sleepTime) {
        this.width = width;
        this.height = height;
        map = new Map(width, height);

        this.numberOfAntStepsInOneUnit = numberOfAntStepsInOneUnit;

        this.numAntsPerLoop = numAntsPerLoop;

        antLocations = new HashMap<Integer, Coordinate>();

        now = new Date();

        idCount = 0;

        this.sleepTime = sleepTime;

        AntManager.antMgr.log(this, "Building world with width " + width + ", height " + height);
        AntManager.antMgr.log(this, "Ant hill is located at " + antHillLocation.toString());
        setPriority(NORM_PRIORITY + 1);
        AntManager.antMgr.logWarn(this, "World complete");
        AntManager.antMgr.worldStarted = true;
    }

    protected Ant addAnt(Counter bearing, Coordinate location, int velocity) {
        AntManager.antMgr.log(this, "Adding ant #" + idCount + "(new) at location " + location.toString() + " bearing " + bearing.getValue() + " degrees");
        Ant newAnt = new Ant(idCount, bearing, velocity, AntManager.antMgr.getAntThreadSleepTime());
        antLocations.put(newAnt.getAntId(), location);
        map.addItem(newAnt, location);
        idCount++;
        return newAnt;
    }

    protected boolean updateAntPath(int id) {
        try {
            AntManager.antMgr.log(this, "Ant #" + id + " path updated to " + AntManager.antMgr.ants.get(id).legs.currentPath.getName());
        } catch (Exception e) {
            AntManager.antMgr.logWarn(this, "Ant #" + id + " path cannot be updated since that ant does not exist.");
            System.err.println("" + e.getMessage() + ":" + e.getLocalizedMessage());
            e.printStackTrace();
        }
        return true;
    }

    protected Coordinate getAntPosition(int antId) {
        Coordinate position = null;
        try {
            position = antLocations.get(antId);
        } catch (Exception e) {

        }
        return position;
    }

    public void run() {
        Boolean endOfTheWorld = false;
        while (AntManager.antMgr.numAntsReady != AntManager.antMgr.getNumLiveAnts()) {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                System.err.println("World was waiting for ants to be ready but was interrupted: " + e.getMessage());
            }
        }
        try {
            AntManager.antMgr.log(this, "Ants ready, starting world interactions.");
            Thread.sleep(500);
        } catch (InterruptedException e) {

        }
        Iterator<Integer> antsToMove = AntManager.antMgr.ants.keySet().iterator();
        while (!endOfTheWorld) {
            // This is where the world does its thing.
            // Namely, move all the items, detect collisions and send out events
            while (AntManager.antMgr.getNumLiveAnts() > 0) {
                try {
                    for (int i = 0; i < numAntsPerLoop; i++) {
                        boolean collision =false;
                        Ant ant;
                        try {
                            ant = AntManager.antMgr.ants.get(antsToMove.next());
                        } catch (NoSuchElementException e) {
                            antsToMove = AntManager.antMgr.ants.keySet().iterator();
                            ant = AntManager.antMgr.ants.get(antsToMove.next());
                        }

                        //Move ant
                        if (ant.legs.currentPath != null) {
                            now = new Date();
                            Segment move = ant.legs.currentPath.getSegment(now.getTime());
                            Coordinate newPosition = new Coordinate(antLocations.get(ant.getAntId()).getX() + move.getWidth(), antLocations.get(ant.getAntId()).getY() + move.getHeight());
                            //Check for collisions
                            if (newPosition.getX() <= 0 || newPosition.getX() >= width) {
                                collision = true;
                            } else if (newPosition.getY() <= 0 || newPosition.getY() >= height) {
                                collision = true;
                            }
                            if(!collision) {
                                if (map.mvItem(ant, antLocations.get(ant.getAntId()), newPosition) != -1) {
                                    antLocations.put(ant.getAntId(), newPosition);
                                }
                            }
                        }
                        //Send out events
                        if(collision) {
                            ant.legs.currentPath = null;
                            ant.queueEvent(new Event(Event.MEETOBSTACLE,0,null));
                        }
                    }
                    Thread.sleep(sleepTime);

                    yield();
                } catch (InterruptedException e) {
                    endOfTheWorld = true;
                }
            }
        }
    }
}
